package unwdmi.connector;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Map;

import unwdmi.app.Server;
import unwdmi.dto.Measurement;

/**
 * A thread that listens for the WeatherStation
 * After the WeatherStation connects to the server it will handle the input
 * If the connection somehow is lost it will listen again
 * @author Stephan E G Veenstra
 * @version 0.0.1
 */

public class WeatherStationConnector implements Runnable {
	
	private Socket stationSocket;
	
	private BufferedReader bin;
	private String stationInput;
	
	public WeatherStationConnector(Socket stationSocket){
		try {
			System.out.println("A weatherServer has connected from: " + stationSocket.getInetAddress());
			this.stationSocket = stationSocket;
			bin = new BufferedReader(new InputStreamReader(stationSocket.getInputStream()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void run() {
		try {

			Measurement m = new Measurement();
			
			while((stationInput = bin.readLine()) != null){
				
				stationInput = stationInput.replaceAll("\\s+", "");
				if(stationInput.equals("<MEASUREMENT>")){
					m = new Measurement();
				}else if(stationInput.equals("</MEASUREMENT>")){
					//Validate the measurements
					this.validateMeasurement(m);
					//Output of the measurement
					//System.out.println(m);
					//Execute measurement
					Server.DB_INSTANCE.createMeasurement(m);
				}else if(stationInput.matches("<\\w+>.+</\\w+>")){
					this.insertInputInMeasurment(m, stationInput);
				}
			}
			System.err.println("Connection with the WeatherStation has been lost!");
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Use a String to fill out a detail of the given measurement
	 * @param m Measurement Object
	 * @param input String with information
	 */
	private void insertInputInMeasurment(Measurement m, String input){
		String key = stationInput.replaceAll("<|>.+>", "");
		String value = stationInput.replaceAll("<\\w+>|</\\w+>", "");
		
		if(key.equals("STN")){
			m.station = Integer.parseInt(value);
		}else if(key.equals("DATE")){
			m.date = value;
		}else if(key.equals("TIME")){
			m.time = value;
		}else if(key.equals("TEMP")){
			m.temperature = Double.parseDouble(value);
		}else if(key.equals("DEWP")){
			m.dewpoint = Double.parseDouble(value);
		}else if(key.equals("STP")){
			m.airpreasureStation = Double.parseDouble(value);
		}else if(key.equals("SLP")){
			m.airpreasureSea = Double.parseDouble(value);
		}else if(key.equals("VISIB")){
			m.visibility = Double.parseDouble(value);
		}else if(key.equals("WDSP")){
			m.windSpeed = Double.parseDouble(value);
		}else if(key.equals("PRCP")){
			m.rainfall = Double.parseDouble(value);
		}else if(key.equals("SNDP")){
			m.snowfall = Double.parseDouble(value);
		}else if(key.equals("FRSHTT")){
			m.freeze = (value.charAt(0) == '1');
			m.rain = (value.charAt(1) == '1');
			m.snow = (value.charAt(2) == '1');
			m.hail = (value.charAt(3) == '1');
			m.thunder = (value.charAt(4) == '1');
			m.tornado = (value.charAt(5) == '1');
		}else if(key.equals("CLDC")){
			m.cloud = Double.parseDouble(value);
		}else if(key.equals("WNDDIR")){
			m.windDirection = Integer.parseInt(value);
		}
	}
	
	/**
	 * Validate the given Measurement Object
	 * @param m Measurement Object
	 * TODO __REFACTOR__
	 */
	private void validateMeasurement(Measurement m) {
		//Get list of previous measures with a limit of 30
		ArrayList<Measurement> measurements = Server.DB_INSTANCE.readMeasurementsByStation(m.getSTN(), m.getDATETIME(), 30);
		double[] set = new double[measurements.size()];
		//-------------------------------------------------------
		if(m.temperature == null) {
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).temperature;
			};
			m.temperature = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.dewpoint == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).dewpoint;
			};
			m.dewpoint = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.airpreasureStation == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).airpreasureStation;
			};
			m.airpreasureStation = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.airpreasureSea == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).airpreasureSea;
			};
			m.airpreasureSea = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.visibility == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).visibility;
			};
			m.visibility = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.windSpeed == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).windSpeed;
			};
			m.windSpeed = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.rainfall == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).rainfall;
			};
			m.rainfall = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.snowfall == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).snowfall;
			};
			m.snowfall = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.cloud == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).cloud;
			};
			m.cloud = this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.windDirection == null){
			for(int i = 0; i < measurements.size(); i++) {
				set[i] = measurements.get(i).windDirection;
			};
			m.windDirection = (int)this.getExtrapolationBySet(set);
		}
		//-------------------------------------------------------
		if(m.freeze == null) { 
			// Check for only one because if one is missing, they all do.
		}
	}
	
	/**
	 * 
	 */
	private double getExtrapolationBySet(double[] set) {
		int i = 1;
		for(; i < set.length-1; i++) {
			set[i] = (set[i] - set[i-1]) + set[i]; 
			System.out.println(set[i]);
		};
		return set[i];
	};
	
}
